import { describe, expect, test } from 'vitest'
import { accounts } from '~test/src/constants.js'
import { signTransaction } from '../accounts/utils/signTransaction.js'
import { zksync } from '../chains/index.js'
import { BaseError } from '../errors/base.js'
import { InvalidChainIdError } from '../errors/chain.js'
import {
  InvalidAddressError,
  parseEther,
  parseGwei,
  parseTransaction,
  type TransactionSerializableEIP1559,
} from '../index.js'
import { serializeTransaction } from './serializers.js'
import type { ZksyncTransactionSerializableEIP712 } from './types/transaction.js'

const baseTransaction: TransactionSerializableEIP1559 = {
  to: '0x111C3E89Ce80e62EE88318C2804920D4c96f92bb',
  chainId: zksync.id,
  nonce: 7,
  maxFeePerGas: 250000000n,
  maxPriorityFeePerGas: 2n,
  value: parseEther('1'),
  data: '0xa4136862000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000017900000000000000000000000000000000000000000000000000000000000000',
}

const baseEip712: ZksyncTransactionSerializableEIP712 = {
  ...baseTransaction,
  from: '0xf760bdd822fccf93c44be68d94c45133002b3037',
  gasPerPubdata: 50000n,
  factoryDeps: [],
  paymaster: '0x4B5DF730c2e6b28E17013A1485E5d9BC41Efe021',
  paymasterInput:
    '0x8c5a344500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000',
  customSignature:
    '0xd2312deb1e84f7733a83ae1fc55f9cc1f2334fe472e0a494781933b194e173a45d927e67b9222b92467660849efb055422f133cf67588cbcb1874901d3244ddd1c',
  type: 'eip712',
}

test('default', () => {
  const transaction: ZksyncTransactionSerializableEIP712 = {
    ...baseEip712,
    gas: 158774n,
  }

  expect(serializeTransaction(transaction)).toMatchInlineSnapshot(
    `"0x71f901500702840ee6b28083026c3694111c3e89ce80e62ee88318c2804920d4c96f92bb880de0b6b3a7640000b864a4136862000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000017900000000000000000000000000000000000000000000000000000000000000820144808082014494f760bdd822fccf93c44be68d94c45133002b303782c350c0b841d2312deb1e84f7733a83ae1fc55f9cc1f2334fe472e0a494781933b194e173a45d927e67b9222b92467660849efb055422f133cf67588cbcb1874901d3244ddd1cf85b944b5df730c2e6b28e17013a1485e5d9bc41efe021b8448c5a344500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000"`,
  )
})

test('gas', () => {
  const transaction: ZksyncTransactionSerializableEIP712 = {
    ...baseEip712,
    gas: 69420n,
  }

  expect(serializeTransaction(transaction)).toMatchInlineSnapshot(
    `"0x71f901500702840ee6b28083010f2c94111c3e89ce80e62ee88318c2804920d4c96f92bb880de0b6b3a7640000b864a4136862000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000017900000000000000000000000000000000000000000000000000000000000000820144808082014494f760bdd822fccf93c44be68d94c45133002b303782c350c0b841d2312deb1e84f7733a83ae1fc55f9cc1f2334fe472e0a494781933b194e173a45d927e67b9222b92467660849efb055422f133cf67588cbcb1874901d3244ddd1cf85b944b5df730c2e6b28e17013a1485e5d9bc41efe021b8448c5a344500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000"`,
  )
})

test('gasPerPubdata', () => {
  const transaction: ZksyncTransactionSerializableEIP712 = {
    ...baseTransaction,
    from: '0xf760bdd822fccf93c44be68d94c45133002b3037',
    gasPerPubdata: 50000n,
    type: 'eip712',
  }

  expect(serializeTransaction(transaction)).toMatchInlineSnapshot(
    `"0x71f8af0702840ee6b2808094111c3e89ce80e62ee88318c2804920d4c96f92bb880de0b6b3a7640000b864a4136862000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000017900000000000000000000000000000000000000000000000000000000000000820144808082014494f760bdd822fccf93c44be68d94c45133002b303782c350c080c0"`,
  )
})

test('factoryDeps', () => {
  const transaction: ZksyncTransactionSerializableEIP712 = {
    ...baseTransaction,
    from: '0xf760bdd822fccf93c44be68d94c45133002b3037',
    factoryDeps: ['0xABCDEF', '0x123456'],
    type: 'eip712',
  }

  expect(serializeTransaction(transaction)).toMatchInlineSnapshot(
    `"0x71f8b70702840ee6b2808094111c3e89ce80e62ee88318c2804920d4c96f92bb880de0b6b3a7640000b864a4136862000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000017900000000000000000000000000000000000000000000000000000000000000820144808082014494f760bdd822fccf93c44be68d94c45133002b303782c350c883abcdef8312345680c0"`,
  )
})

test('customSignature', () => {
  const transaction: ZksyncTransactionSerializableEIP712 = {
    ...baseTransaction,
    from: '0xf760bdd822fccf93c44be68d94c45133002b3037',
    customSignature: '0xABCDEF',
    type: 'eip712',
  }

  expect(serializeTransaction(transaction)).toMatchInlineSnapshot(
    `"0x71f8b20702840ee6b2808094111c3e89ce80e62ee88318c2804920d4c96f92bb880de0b6b3a7640000b864a4136862000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000017900000000000000000000000000000000000000000000000000000000000000820144808082014494f760bdd822fccf93c44be68d94c45133002b303782c350c083abcdefc0"`,
  )
})

test('paymaster', () => {
  const transaction: ZksyncTransactionSerializableEIP712 = {
    ...baseTransaction,
    from: '0xf760bdd822fccf93c44be68d94c45133002b3037',
    paymaster: '0x4B5DF730c2e6b28E17013A1485E5d9BC41Efe021',
    paymasterInput:
      '0x8c5a344500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000',
    type: 'eip712',
  }

  expect(serializeTransaction(transaction)).toMatchInlineSnapshot(
    `"0x71f9010b0702840ee6b2808094111c3e89ce80e62ee88318c2804920d4c96f92bb880de0b6b3a7640000b864a4136862000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000017900000000000000000000000000000000000000000000000000000000000000820144808082014494f760bdd822fccf93c44be68d94c45133002b303782c350c080f85b944b5df730c2e6b28e17013a1485e5d9bc41efe021b8448c5a344500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000"`,
  )
})

test('without nonce', () => {
  const transaction: ZksyncTransactionSerializableEIP712 = {
    ...baseEip712,
    nonce: undefined,
  }

  expect(serializeTransaction(transaction)).toMatchInlineSnapshot(
    `"0x71f9014d8002840ee6b2808094111c3e89ce80e62ee88318c2804920d4c96f92bb880de0b6b3a7640000b864a4136862000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000017900000000000000000000000000000000000000000000000000000000000000820144808082014494f760bdd822fccf93c44be68d94c45133002b303782c350c0b841d2312deb1e84f7733a83ae1fc55f9cc1f2334fe472e0a494781933b194e173a45d927e67b9222b92467660849efb055422f133cf67588cbcb1874901d3244ddd1cf85b944b5df730c2e6b28e17013a1485e5d9bc41efe021b8448c5a344500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000"`,
  )
})

test('without fees', () => {
  const transaction: ZksyncTransactionSerializableEIP712 = {
    ...baseEip712,
    maxFeePerGas: undefined,
    maxPriorityFeePerGas: undefined,
  }

  expect(serializeTransaction(transaction)).toMatchInlineSnapshot(
    `"0x71f901490780808094111c3e89ce80e62ee88318c2804920d4c96f92bb880de0b6b3a7640000b864a4136862000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000017900000000000000000000000000000000000000000000000000000000000000820144808082014494f760bdd822fccf93c44be68d94c45133002b303782c350c0b841d2312deb1e84f7733a83ae1fc55f9cc1f2334fe472e0a494781933b194e173a45d927e67b9222b92467660849efb055422f133cf67588cbcb1874901d3244ddd1cf85b944b5df730c2e6b28e17013a1485e5d9bc41efe021b8448c5a344500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000"`,
  )
})

test('without to', () => {
  const transaction: ZksyncTransactionSerializableEIP712 = {
    ...baseEip712,
    to: undefined,
  }

  expect(serializeTransaction(transaction)).toMatchInlineSnapshot(
    `"0x71f901390702840ee6b2808080880de0b6b3a7640000b864a4136862000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000017900000000000000000000000000000000000000000000000000000000000000820144808082014494f760bdd822fccf93c44be68d94c45133002b303782c350c0b841d2312deb1e84f7733a83ae1fc55f9cc1f2334fe472e0a494781933b194e173a45d927e67b9222b92467660849efb055422f133cf67588cbcb1874901d3244ddd1cf85b944b5df730c2e6b28e17013a1485e5d9bc41efe021b8448c5a344500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000"`,
  )
})

test('without value', () => {
  const transaction: ZksyncTransactionSerializableEIP712 = {
    ...baseEip712,
    value: undefined,
  }

  expect(serializeTransaction(transaction)).toMatchInlineSnapshot(
    `"0x71f901450702840ee6b2808094111c3e89ce80e62ee88318c2804920d4c96f92bb80b864a4136862000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000017900000000000000000000000000000000000000000000000000000000000000820144808082014494f760bdd822fccf93c44be68d94c45133002b303782c350c0b841d2312deb1e84f7733a83ae1fc55f9cc1f2334fe472e0a494781933b194e173a45d927e67b9222b92467660849efb055422f133cf67588cbcb1874901d3244ddd1cf85b944b5df730c2e6b28e17013a1485e5d9bc41efe021b8448c5a344500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000"`,
  )
})

test('without data', () => {
  const transaction: ZksyncTransactionSerializableEIP712 = {
    ...baseEip712,
    data: undefined,
  }

  expect(serializeTransaction(transaction)).toMatchInlineSnapshot(
    `"0x71f8e80702840ee6b2808094111c3e89ce80e62ee88318c2804920d4c96f92bb880de0b6b3a764000080820144808082014494f760bdd822fccf93c44be68d94c45133002b303782c350c0b841d2312deb1e84f7733a83ae1fc55f9cc1f2334fe472e0a494781933b194e173a45d927e67b9222b92467660849efb055422f133cf67588cbcb1874901d3244ddd1cf85b944b5df730c2e6b28e17013a1485e5d9bc41efe021b8448c5a344500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000"`,
  )
})

test('without from', () => {
  const transaction: ZksyncTransactionSerializableEIP712 = {
    ...baseEip712,
    // @ts-expect-error
    from: undefined,
  }

  expect(serializeTransaction(transaction)).toMatchInlineSnapshot(
    `"0x71f901390702840ee6b2808094111c3e89ce80e62ee88318c2804920d4c96f92bb880de0b6b3a7640000b864a413686200000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001790000000000000000000000000000000000000000000000000000000000000082014480808201448082c350c0b841d2312deb1e84f7733a83ae1fc55f9cc1f2334fe472e0a494781933b194e173a45d927e67b9222b92467660849efb055422f133cf67588cbcb1874901d3244ddd1cf85b944b5df730c2e6b28e17013a1485e5d9bc41efe021b8448c5a344500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000"`,
  )
})

test('signed with customSignature', async () => {
  const signed = await signTransaction({
    privateKey: accounts[0].privateKey,
    transaction: { ...baseEip712, gas: 158774n },
    serializer: serializeTransaction,
  })

  expect(signed).toMatchInlineSnapshot(
    `"0x71f901500702840ee6b28083026c3694111c3e89ce80e62ee88318c2804920d4c96f92bb880de0b6b3a7640000b864a4136862000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000017900000000000000000000000000000000000000000000000000000000000000820144808082014494f760bdd822fccf93c44be68d94c45133002b303782c350c0b841d2312deb1e84f7733a83ae1fc55f9cc1f2334fe472e0a494781933b194e173a45d927e67b9222b92467660849efb055422f133cf67588cbcb1874901d3244ddd1cf85b944b5df730c2e6b28e17013a1485e5d9bc41efe021b8448c5a344500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000"`,
  )
})

describe('invalid params', () => {
  test('invalid paymaster', () => {
    const transaction: ZksyncTransactionSerializableEIP712 = {
      ...baseEip712,
      paymaster: '0xdeadbeef',
    }
    expect(() => serializeTransaction(transaction)).toThrowError(
      InvalidAddressError,
    )
  })

  test('invalid chain', () => {
    const transaction: ZksyncTransactionSerializableEIP712 = {
      ...baseEip712,
      paymaster: '0x4B5DF730c2e6b28E17013A1485E5d9BC41Efe021',
      chainId: -1,
    }
    expect(() => serializeTransaction(transaction)).toThrowError(
      InvalidChainIdError,
    )
  })

  test('invalid to', () => {
    const transaction: ZksyncTransactionSerializableEIP712 = {
      ...baseEip712,
      paymaster: '0x4B5DF730c2e6b28E17013A1485E5d9BC41Efe021',
      to: '0xdeadbeef',
    }
    expect(() => serializeTransaction(transaction)).toThrowError(
      InvalidAddressError,
    )
  })

  test('invalid from', () => {
    const transaction: ZksyncTransactionSerializableEIP712 = {
      ...baseEip712,
      paymaster: '0x4B5DF730c2e6b28E17013A1485E5d9BC41Efe021',
      from: '0xdeadbeef',
    }
    expect(() => serializeTransaction(transaction)).toThrowError(
      InvalidAddressError,
    )
  })

  test('missing paymaster', () => {
    const transaction: ZksyncTransactionSerializableEIP712 = {
      ...baseTransaction,
      from: '0xf760bdd822fccf93c44be68d94c45133002b3037',
      paymasterInput:
        '0x8c5a344500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000',
      type: 'eip712',
    }
    expect(() => serializeTransaction(transaction)).toThrowError(BaseError)
  })

  test('missing paymasterInput', () => {
    const transaction: ZksyncTransactionSerializableEIP712 = {
      ...baseTransaction,
      from: '0xf760bdd822fccf93c44be68d94c45133002b3037',
      paymaster: '0x4B5DF730c2e6b28E17013A1485E5d9BC41Efe021',
      type: 'eip712',
    }
    expect(() => serializeTransaction(transaction)).toThrowError(BaseError)
  })
})

test('other', () => {
  const transaction: TransactionSerializableEIP1559 = {
    to: accounts[0].address,
    chainId: 1,
    nonce: 0,
    maxFeePerGas: parseGwei('2'),
    maxPriorityFeePerGas: parseGwei('2'),
    value: parseEther('1'),
  }
  const serialized = serializeTransaction(transaction)
  expect(serialized).toMatchInlineSnapshot(
    '"0x02ed0180847735940084773594008094f39fd6e51aad88f6f4ce6ab8827279cfffb92266880de0b6b3a764000080c0"',
  )
  expect(parseTransaction(serialized)).toEqual({
    to: accounts[0].address,
    chainId: 1,
    nonce: 0,
    maxFeePerGas: parseGwei('2'),
    maxPriorityFeePerGas: parseGwei('2'),
    value: parseEther('1'),
    type: 'eip1559',
  })
})
